package com.example.bbs.util;

import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bumptech.glide.RequestBuilder;
import com.example.bbs.R;
import com.example.bbs.base.Data;
import com.example.bbs.config.HttpConstant;
import com.facebook.stetho.okhttp3.StethoInterceptor;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;

public class HttpUtil {

    public interface HttpCallback extends Callback {

        void onHttpResponse(JSONObject obj);

        @Override
        default void onFailure(@NonNull Call call, @NonNull IOException e) {
            try {
                BaseUtil.showToast(R.string.toast_network);
            } catch (Exception ignored) {}
            Log.e(LOG_TAG, "http request failed");
        }

        @Override
        default void onResponse(@NotNull Call call, @NotNull Response response) {
            if (response.code() != 200) {
                Log.e(LOG_TAG, "http communication failed, code: " + response.code());
                onHttpResponse(null);
                return;
            }
            String responseStr = "{}";
            try {
                responseStr = Objects.requireNonNull(response.body()).string();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                JSONObject obj = JSON.parseObject(responseStr);
                onHttpResponse(obj);
            } catch (Exception e) {
                e.printStackTrace();
                Log.e(LOG_TAG, "http response parsing error: response: " + responseStr);
            }
        }
    }

    static final String LOG_TAG = HttpUtil.class.getSimpleName();
    static final long READ_TIMEOUT = 5 * 1000; // millisecond
    static final long WRITE_TIMEOUT = 5 * 1000; // millisecond
    static final long CONNECT_TIMEOUT = 5 * 1000; // millisecond
    static final long HTTP_RESPONSE_CACHE_MAX_SIZE = 10 * 1024 * 1024;

    static OkHttpClient okHttpClient;
    static HttpLoggingInterceptor interceptor;

    public static void init(Context inContext) {
        interceptor = new HttpLoggingInterceptor(message -> {
            try {
                Log.i(LOG_TAG, message);
            } catch (Exception e) {
                e.printStackTrace();
                Log.w(LOG_TAG, message);
            }
        });
        interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); // 详细信息用 stetho 查看

        okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .addNetworkInterceptor(new StethoInterceptor())
                .cache(new Cache(inContext.getCacheDir(), HTTP_RESPONSE_CACHE_MAX_SIZE))
                .readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
                .writeTimeout(WRITE_TIMEOUT, TimeUnit.MILLISECONDS)
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
                .build();

        JSONObject response = post(HttpConstant.REQUEST_HELLO, "");
        // 检查请求回复
        if (response != null && response.getBoolean(HttpConstant.FIELD_REPLY))
            BaseUtil.importantLog(LOG_TAG, "Network OK !");
        else
            Log.e(LOG_TAG, "Network failed");
    }

    static Request generateRequest(String uri, RequestBody requestBody) {
        String url = HttpConstant.SERVER_URL + uri + '/';
        try {
            Request.Builder requestBuilder = new Request.Builder().url(url);
            if (requestBody != null)
                requestBuilder.post(requestBody);
            if (Data.myself != null) {
                requestBuilder.addHeader("token", Data.myself.getToken());
            }
            return requestBuilder.build();
        } catch (Exception e) {
            e.printStackTrace();
            Log.w(LOG_TAG, "constructing post failed: " + url + " " + requestBody);
            return null;
        }
    }

    public static JSONObject post(String uri, RequestBody requestBody) {
        Response response = null;
        try {
            response = okHttpClient.newCall(
                    Objects.requireNonNull(generateRequest(uri, requestBody))).execute();
        } catch (IOException e) {
            Log.w(LOG_TAG, "send post failed");
            return null;
        }
        try {
            if (response.code() != 200)
                return null; // 打印错误的任务交给 okhttp3 interceptor 处理
            String strResponse = Objects.requireNonNull(response.body()).string();
            return JSON.parseObject(strResponse);
        } catch (Exception e) {
            Log.w(LOG_TAG, "parsing response failed");
            e.printStackTrace();
            return null;
        }
    }

    public static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8");

    public static JSONObject post(String uri, String json) {
        RequestBody body = RequestBody.create(json, JSON_TYPE);
        return post(uri, body);
    }

    public static void postAsync(String uri, RequestBody requestBody, HttpCallback callback) {
        okHttpClient.newCall(Objects.requireNonNull(generateRequest(uri, requestBody))).enqueue(callback);
    }

    public static void postAsync(String uri, String json, HttpCallback callback) {
        RequestBody body = RequestBody.create(json, JSON_TYPE);
        postAsync(uri, body, callback);
    }
}
